﻿using Utils;

namespace Pap.Web.Modules.Loan.ViewModel
{
    using System;
    using System.Collections;
    using System.Linq;

    using Microsoft.Practices.ServiceLocation;

    using Pap.Core.Utilities;
    using Pap.Data;
    using Pap.Data.Abstraction.Utils;
    using Pap.Services;
    using Pap.Services.WorkflowEngine;
    using Pap.Web.Utils;

    using Utils;

    // public class PaymentVi

    /// <summary>
    /// 
    /// </summary>
    public class InstallmentsPaymentViewModel : IViewModel
    {
        #region Fields

        /// <summary>
        /// 
        /// </summary>
        IAdministrationRepository _AdminstrationRepository;

        /// <summary>
        /// 
        /// </summary>
        ILoanExecutionService _LoanExecutionService;

        /// <summary>
        /// 
        /// </summary>
        ILoanRepository _LoanRepository;

        /// <summary>
        /// 
        /// </summary>
        IWorkflowService _WorkFlowService;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="InstallmentsPaymentViewModel"/> class.
        /// </summary>
        /// <param name="LoanRepository">The loan repository.</param>
        /// <param name="LoanExecutionService">The loan execution service.</param>
        /// <param name="workFlowService">The work flow service.</param>
        /// <param name="adminRepository">The admin repository.</param>
        public InstallmentsPaymentViewModel(ILoanRepository LoanRepository, ILoanExecutionService LoanExecutionService, IWorkflowService workFlowService, IAdministrationRepository adminRepository)
        {
            _LoanRepository = LoanRepository;
            _LoanExecutionService = LoanExecutionService;
            _WorkFlowService = workFlowService;
            _AdminstrationRepository = adminRepository;
        }

        #endregion Constructors

        #region Methods
        /// <summary>
        /// Gets the loan execution.
        /// </summary>
        /// <param name="installmentId">The loan installment Id.</param>
        /// <returns></returns>
        public ILoanExecutionInstallment GetLoanInstallment(Guid installmentId)
        {
            return _LoanRepository.GetLoanExecutionInstallment(installmentId);
        }
        /// <summary>
        /// Gets the loan excution payments.
        /// </summary>
        /// <param name="installment">The loan installment.</param>
        /// <returns></returns>
        public IEnumerable GetLoanExcutionPayments(ILoanExecutionInstallment installment)
        {
            var loanPayments = installment.LoanExecution.LoanExecutionInstallmentsLst.SelectMany(loanInstall => loanInstall.LoanInstallmentPaymentLst);
            return (from loanPayment in loanPayments
                    select new
                               {
                                   PaymentDate = loanPayment.PaymentDate,
                                   PaymentAmount = loanPayment.PaymentAmount,
                                   ReceiptNumber = loanPayment.ReciptObj.ReceiptNumber,
                                   InstallmentDueDate = loanPayment.LoanExecutionInstallment.InstallmentDate
                               });
        }

        public double GetLoanDueAmount(ILoanExecutionInstallment installment)
        {
            var totalPaied = installment.LoanInstallmentPaymentLst.Sum(x => x.PaymentAmount);
            return (installment.TotalInstallmentAmount + installment.PenaltyAmount - totalPaied);
        }

        /// <summary>
        /// Gets the old date.
        /// </summary>
        /// <param name="installment">The installment.</param>
        /// <returns></returns>
        public DateTime? GetOldDate(ILoanExecutionInstallment installment)
        {
            var loanStep = _WorkFlowService.GetStep(
                _WorkFlowService.GetProcessInstanceIDByEntity(installment.LoanExecution.CustomerLoan.LoanID));
            return loanStep.CompletionDate;
        }

        /// <summary>
        /// Determines whether [is automatic receipte mode].
        /// </summary>
        /// <returns>
        ///   <c>true</c> if [is automatic receipte mode]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsAutomaticReceipteMode()
        {
            long seed = int.Parse(_AdminstrationRepository.GetSettingValue(RegistryInfo.CommitteeID, SettingKeys.ReceiptSeed));
            if (seed == -1)
                return false;
            return true;
        }

        /// <summary>
        /// Pays the instalment.
        /// </summary>
        /// <param name="installmentId">The installment Id.</param>
        /// <param name="paymentAmount">The payment amount.</param>
        /// <param name="receipteNumber">The receipte number.</param>
        /// <param name="paymentDate">The payment date.</param>
        /// <returns></returns>
        public IReceipt PayInstallment(Guid installmentId, double paymentAmount, string receipteNumber, DateTime paymentDate)
        {
            IReceipt recipt;
            using (IUnitOfWork transaction = ServiceLocator.Current.GetInstance<IUnitOfWork>())
            {
                long receiptNum = GetNewLoanReceipt(receipteNumber);
                recipt =_LoanExecutionService.PayInstallment(installmentId, paymentAmount, receiptNum, paymentDate);
                transaction.Commit();
            }

            // is the loan totally paid.
            var installment = GetLoanInstallment(installmentId);
            if (_LoanRepository.FindLoanExecutionInstallments(l => l.LoanExecutionID == installment.LoanExecutionID && !l.IsPaid).Count() == 0)
            {
                using (IUnitOfWork transaction = ServiceLocator.Current.GetInstance<IUnitOfWork>())
                {
                    Guid procinstid = _WorkFlowService.GetProcessInstanceIDByEntity(installment.LoanExecution.LoanID);
                    _WorkFlowService.Move(ActionTypes.Close, procinstid, RegistryInfo.UserID,
                                          _WorkFlowService.GetStep(procinstid).PreviousNotes, null);

                    //add loan to loan history
                    ICustomerLoanHistory loanhistory;
                    if (
                        _LoanRepository.FindLoanExecutions(
                            loanex => loanex.LoanID.Equals(installment.LoanExecution.LoanID))
                            .Count() > 1)
                        loanhistory = _LoanExecutionService.GetLoanHistory(installment.LoanExecution,
                                                                           LoanHistoryCloseTypes.ReScheduling,
                                                                           string.Empty);
                    else
                        loanhistory = _LoanExecutionService.GetLoanHistory(installment.LoanExecution,
                                                                           LoanHistoryCloseTypes.ClosedSuccessfuly,
                                                                           string.Empty);

                    _LoanRepository.CreateCustomerLoanHistory(loanhistory);
                    transaction.Commit();
                }
            }
            return recipt;
        }

        /// <summary>
        /// Gets the new loan receipt.
        /// </summary>
        /// <param name="manualReceiptNumber">The manual receipt number.</param>
        /// <returns></returns>
        private long GetNewLoanReceipt(string manualReceiptNumber)
        {
            Guid newLoanReceiptTypeID = Enums.ToString(ReceiptTypes.InstallmentReceipt).ToGuid();

            long seed = int.Parse(_AdminstrationRepository.GetSettingValue(RegistryInfo.CommitteeID, SettingKeys.ReceiptSeed));
            if (seed != -1 || manualReceiptNumber.IsNullOrEmpty())
            {
                var receipts = _LoanRepository.FindReceipts(r => r.ReceiptTypeID == newLoanReceiptTypeID);
                long receiptNumber = 0;
                if (receipts.Count() > 0)
                    receiptNumber = receipts.Max(r => r.ReceiptNumber);
                return receiptNumber + 1;
            }
            return long.Parse(manualReceiptNumber);
        }

        #endregion Methods
    }
}